package com.simen.myapplication.androidnetworkservicediscoverydemo

import android.content.Context
import android.net.nsd.NsdManager
import android.net.nsd.NsdServiceInfo
import android.os.Build
import android.os.Build.*
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.AdapterView
import android.widget.Spinner
import android.widget.TextView
import java.net.InetAddress
import java.net.ServerSocket

class MainActivity : AppCompatActivity() {

    companion object {
        private const val TAG = "MainActivity"
        private var SERVICE_TYPE = "_nsdchat._tcp"
        private var SERVICE_NAME = "NsdChat_$MODEL"
    }

    var contentTextView: TextView?=null;
    var serviceTypeSpinner: Spinner?=null;

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        contentTextView=findViewById<TextView>(R.id.content)
        serviceTypeSpinner=findViewById<Spinner>(R.id.serviceType)
        nsdManager = (getSystemService(Context.NSD_SERVICE) as NsdManager)

        apply{
            title= SERVICE_NAME
        }

        serviceTypeSpinner?.apply{
            onItemSelectedListener=object : AdapterView.OnItemSelectedListener{
                override fun onNothingSelected(parent: AdapterView<*>?) {
                }

                override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
                    //var serviceTypes:String[]
                    var serviceTypes=resources.getStringArray(R.array.serviceTypes)

                    SERVICE_TYPE=serviceTypes[position]
                }
            }
        }
    }


    override fun onDestroy() {
        tearDown()
        super.onDestroy()
    }

    // NsdHelper's tearDown method
    private fun tearDown() {
        nsdManager.apply {
            try{
                unregisterService(registrationListener)
            }catch (e:IllegalArgumentException){
                e.printStackTrace()
            }
            try{
                stopServiceDiscovery(discoveryListener)
            }catch (e:IllegalArgumentException){
                e.printStackTrace()
            }
        }
    }

    /*- - - - 在网络上注册您的服务 start - - - -*/
    private var mServiceName: String?=null
    private var mLocalPort: Int=0
    private lateinit var serverSocket: ServerSocket
    private lateinit var nsdManager: NsdManager

    private fun registerService(port: Int) {
        // Create the NsdServiceInfo object, and populate it.
        val serviceInfo = NsdServiceInfo().apply {
            // The name is subject to change based on conflicts
            // with other services advertised on the same network.
            serviceName = SERVICE_NAME
            serviceType = SERVICE_TYPE
            setPort(port)
        }

        nsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, registrationListener)
    }

    private fun initializeServerSocket() {
        // Initialize a server socket on the next available port.
        serverSocket = ServerSocket(0).also { socket ->
            // Store the chosen port.
            mLocalPort = socket.localPort
        }
    }

    private val registrationListener = object : NsdManager.RegistrationListener {

        override fun onServiceRegistered(NsdServiceInfo: NsdServiceInfo) {
            log(TAG, "onServiceRegistered: ")
            // Save the service name. Android may have changed it in order to
            // resolve a conflict, so update the name you initially requested
            // with the name Android actually used.
            mServiceName = NsdServiceInfo.serviceName
            log(TAG, "service name&type: $mServiceName ${NsdServiceInfo.serviceType}")
        }

        override fun onRegistrationFailed(serviceInfo: NsdServiceInfo, errorCode: Int) {
            log(TAG, "onRegistrationFailed: $errorCode")
            // Registration failed! Put debugging code here to determine why.
        }

        override fun onServiceUnregistered(arg0: NsdServiceInfo) {
            log(TAG, "onServiceUnregistered: ")
            // Service has been unregistered. This only happens when you call
            // NsdManager.unregisterService() and pass in this listener.
        }

        override fun onUnregistrationFailed(serviceInfo: NsdServiceInfo, errorCode: Int) {
            log(TAG, "onUnregistrationFailed: $errorCode")
            // Unregistration failed. Put debugging code here to determine why.
        }
    }

    fun registerService(view: View) {
        initializeServerSocket()
        registerService(mLocalPort)
    }

    fun unRegisterService(view: View) {
        try {
            nsdManager.unregisterService(registrationListener)
        }catch (e:IllegalArgumentException){
            e.printStackTrace()
        }
        serverSocket.close()
    }
    /*- - - - 在网络上注册您的服务 end - - - -*/

    /*- - - - 发现网络上的服务 start - - - -*/
    private lateinit var mService: NsdServiceInfo

    private val resolveListener = object :NsdManager.ResolveListener{
        override fun onResolveFailed(serviceInfo: NsdServiceInfo, errorCode: Int) {
            // Called when the resolve fails. Use the error code to debug.
            log(TAG,"Resolve failed: $errorCode")
        }

        override fun onServiceResolved(serviceInfo: NsdServiceInfo) {
            log(TAG, "Resolve Succeeded. $serviceInfo")

            if (serviceInfo.serviceName == mServiceName) {
                log(TAG, "Same IP.")
                return
            }
            mService = serviceInfo
            val port: Int = serviceInfo.port
            val host: InetAddress = serviceInfo.host
        }
    }

    private fun log(tag: String, msg: String) {
        Log.i(TAG, msg)
        runOnUiThread {
            contentTextView?.append("$tag $msg\n")
        }
    }

    // Instantiate a new DiscoveryListener
    private val discoveryListener = object : NsdManager.DiscoveryListener {

        // Called as soon as service discovery begins.
        override fun onDiscoveryStarted(regType: String) {
            log(TAG, "Service discovery started")
        }

        override fun onServiceFound(service: NsdServiceInfo) {
            // A service was found! Do something with it.
            log(TAG, "Service discovery success $service")
            var serviceType:String=service.serviceType;

            when{
                serviceType.last()=='.' -> {
                    serviceType = serviceType.substring(0, serviceType.length - 1)
                }
            }
            when {
                serviceType != SERVICE_TYPE -> // Service type is the string containing the protocol and
                    // transport layer for this service.
                    log(TAG, "Unknown Service Type: ${service.serviceType}")
                service.serviceName == mServiceName -> // The name of the service tells the user what they'd be
                    // connecting to. It could be "Bob's Chat App".
                    log(TAG, "Same machine: $mServiceName")
                service.serviceName.contains("NsdChat") -> nsdManager.resolveService(service, resolveListener)
            }
        }

        override fun onServiceLost(service: NsdServiceInfo) {
            // When the network service is no longer available.
            // Internal bookkeeping code goes here.
            log(TAG, "service lost: $service")
        }

        override fun onDiscoveryStopped(serviceType: String) {
            log(TAG, "Discovery stopped: $serviceType")
        }

        override fun onStartDiscoveryFailed(serviceType: String, errorCode: Int) {
            log(TAG, "Discovery failed: Error code:$errorCode")
            nsdManager.stopServiceDiscovery(this)
        }

        override fun onStopDiscoveryFailed(serviceType: String, errorCode: Int) {
            log(TAG, "Discovery failed: Error code:$errorCode")
            nsdManager.stopServiceDiscovery(this)
        }
    }

    fun discoveryService(view: View) {
        nsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryListener)
    }
    /*- - - - 发现网络上的服务 end - - - -*/

    fun clearLog(view: View) {
        contentTextView!!.text="空"
    }

}

